﻿using System.ComponentModel;
using ICSharpCode.NRefactory.CSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using Microsoft.Data.Schema.ScriptDom.Sql;
using Microsoft.Data.Schema.ScriptDom;

namespace ATTAR
{
    public enum Status
    {
        PASS = 0,
        FAIL = 1
    };

    public class ECHOValidator
    {
        private Status overallStatus;
        private string filePath;
        private List<ECHOValidation> selectedValidations;
        private ECHOElements elements;
        private RichTextBox reportColoredBox;

        #region Constant labels for report

        /// <summary>
        /// The database backup header.
        /// </summary>
        private const string DatabaseBackupHeader =
            "\r\nDatabase must be backed up  and rolled back at teardown, if modified during the test: ";

        /// <summary>
        /// The timeout header.
        /// </summary>
        private const string TimeoutHeader =
            "\r\nTest overall time must be greater than the sum of testcases timeouts: ";

        /// <summary>
        /// The zero timeout header.
        /// </summary>
        private const string zeroTimeoutHeader = "\r\nNo [Timeout] value of 0: ";

        /// <summary>
        /// The cat attribute header.
        /// </summary>
        private const string CatAttributeHeader = "\r\nEach test class must have a [Category] and [Author] attributes: ";

        /// <summary>
        /// The conditional statements header.
        /// </summary>
        private const string ConditionalStatementsHeader = "\r\nNo conditional statements: ";

        /// <summary>
        /// The try catch header.
        /// </summary>
        private const string TryCatchHeader = "\r\nNo Try-Catch or Try-Finally: ";

        /// <summary>
        /// The no database outside echo header.
        /// </summary>
        private const string NoDatabaseOutsideEchoHeader =
            "\r\nNo use of database connections outside those provided by Echo: ";

        /// <summary>
        /// The sleeps header.
        /// </summary>
        private const string SleepsHeader = "\r\nNo use of Thread.sleep(): ";

        /// <summary>
        /// The console header.
        /// </summary>
        private const string ConsoleHeader = "\r\nDoes not call System.Console or Console.Log: ";

        /// <summary>
        /// The bdd header.
        /// </summary>
        private const string BDDHeader = "\r\nUse of BDD test cases format (Given, When, Then, And): ";

        /// <summary>
        /// The lambda header.
        /// </summary>
        private const string LambdaHeader =
            "\r\nNo use of 1 or 2 letters lambda expressions (ie. x => x.  or xy => xy.): ";

        /// <summary>
        /// The cache refresh header.
        /// </summary>
        private const string CacheRefreshHeader = "\r\nUse cache refresh insetead of IIS reset when posible: ";

        /// <summary>
        /// The corporate comments header.
        /// </summary>
        private const string CorporateCommentsHeader = "\r\nUse of standar corporate header coments: ";

        /// <summary>
        /// The metadata header.
        /// </summary>
        private const string MetadataHeader = "\r\nAll methods should have metadata (xml documentation): ";

        /// <summary>
        /// The teardown critical functions header.
        /// </summary>
        private const string TeardownCriticalFunctionsHeader =
            "\r\nAll critical functions in the fixture teardown must be placed before doing any GUI interaction: ";

        /// <summary>
        /// The usings sorted header.
        /// </summary>
        private const string UsingsSortedHeader = "\r\nUsings are to be on top and sorted: ";

        /// <summary>
        /// The variables header.
        /// </summary>
        private const string VariablesHeader = "\r\nVariables and Constant declarations should be at the top: ";

        /// <summary>
        /// The set up at top header.
        /// </summary>
        private const string SetUpAtTopHeader =
            "\r\nFixture setup and fixture teardown should be at the top right after variables and constants declaration: ";

        /// <summary>
        /// The helpers at bottom header.
        /// </summary>
        private const string HelpersAtBottomHeader =
            "\r\nHelpers (private methods) should be at the bottom after Test cases (public methods): ";

        /// <summary>
        /// The concatenating header.
        /// </summary>
        private const string ConcatenatingHeader =
            "\r\nUse of string.Format instead of concatenating string using \"x\" + \"y\": ";

        private const string NamespaceMatchesFolderStructureHeader = "\r\nAccurate 'Namespace' that follows folder hierarchy: ";

        private int failCount = 0;

        private const string PASSED = "PASSED\r\n";
        private const string FAILED = "FAILED\r\n";

        #endregion

        public ECHOValidator(string filePath, ValidationConfiguration configuration, ECHOElements elements, ref RichTextBox reportColoredBox)
        {
            this.filePath = filePath;

            var validations = from valid in configuration.Validations
                              where valid.Enabled
                              select valid;

            this.selectedValidations = validations.ToList() as List<ECHOValidation>;
            this.elements = elements;
            this.reportColoredBox = reportColoredBox;
            this.overallStatus = Status.PASS;
        }

        public Status Validate()
        {
            foreach (ECHOValidation validation in selectedValidations)
            {
                switch (validation.Code)
                {
                    case "ModifiedDatabaseIsBackedUpAndRestored":
                        {
                            try
                            {
                                if (!ValidateModifiedDatabaseIsBackedUpAndRestored()) // 0                                
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            {

                            }
                        }
                        break;
                    case "OverallTimeout":
                        {
                            try
                            {
                                if (!ValidateOverallTimeout())
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            {
                            }
                        }
                        break;
                    case "NoTimeOutOfZero":
                        {
                            try
                            {
                                if (!ValidateZeroTimeouts())
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            {

                            }
                        }

                        break;
                    case "RequiredCategoryAndAuthorAttributes":
                        {
                            try
                            {
                                if (!ValidateRequiredCategoryAndAuthorAttributes()) // 3
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            {
                            }
                        }
                        break;
                    case "NoConditionalStatements":
                        {
                            try
                            {
                                if (!ValidateNoConditionalStatements()) // 4
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            {
                            }
                        }
                        break;
                    case "TryStatements":
                        {
                            try
                            {
                                if (!ValidateTryStatements()) // 5
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            {
                            }
                        }
                        break;
                    case "NoUseOfDatabaseConnectionsOutsideThoseProvidedByEcho":
                        {
                            try
                            {
                                if (!ValidateNoUseOfDatabaseConnectionsNotProvidedByECHO()) // 6
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        } break;
                    case "NoThreadSleeps":
                        {
                            try
                            {
                                if (!ValidateNoThreadSleeps()) // 7
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "NoSystemConsoleOrSystemLogUsage":
                        {
                            try
                            {
                                if (!ValidateNoSystemConsoleOrSystemLogUsage()) // 8
                                    overallStatus = Status.FAIL;

                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "TestsFollowBDD":
                        {
                            try
                            {
                                if (!ValidateTestsFollowBDD()) // 9
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "DescriptiveLambdaExpressions":
                        {
                            try
                            {
                                if (!ValidateDescriptiveLambdaExpressions()) // 10
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "UseCacheRefreshInseteadOfIISResetWhenPosible":
                        {
                            try
                            {
                                // "Use cache refresh insetead of IIS reset when posible",  11
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "UseOfStandardCorporateHeaderComents":
                        {
                            try
                            {
                                // "Use of standar corporate header coments", 12
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "AllMethodsShouldHaveMetadataXmlDocumentation":
                        {
                            try
                            {
                                // "All methods should have metadata (xml documentation)", 13
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "AllCriticalFunctionsInTheFixtureTeardownMustBePlacedBeforeDoingAnyGUIinteraction":
                        {
                            try
                            {
                                // "All critical functions in the fixture teardown must be placed before doing any GUI interaction",  14
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "Usings":
                        {
                            try
                            {
                                if (!ValidateUsings()) // 15
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "VariablesAndConstantDeclarationsShouldBeAtTheTop":
                        {
                            try
                            {
                                // "Variables and Constant declarations should be at the top ",  16
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "FixtureSetupAndFixtureTeardownLocation":
                        {
                            try
                            {
                                if (!ValidateFixtureSetupAndFixtureTeardownLocation()) // 17
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "HelpersMethodsShouldBeAtTheBottomAfterTestCases":
                        {
                            try
                            {
                                // "Helpers (private methods) should be at the bottom after Test cases (public methods)", 18
                            }
                            catch (System.Exception ex)
                            { }
                        }

                        break;
                    case "UseOfStringFormat":
                        {
                            try
                            {
                                // "Use of string.Format instead of concatenating string using \"x\" + \"y\""});  //19
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                    case "MatchingNamespaceAndFolderStructure":
                        {
                            try
                            {
                                if (!ValidateNamespaceMatchesFolderStructure())
                                    overallStatus = Status.FAIL;
                            }
                            catch (System.Exception ex)
                            { }
                        }
                        break;
                }
            }

            return overallStatus;
        }

        private bool ValidateNamespaceMatchesFolderStructure()
        {
            bool validated = true;

            string validateNamespaceMatchesFolderStructure = string.Empty;

            this.reportColoredBox.AppendText(NamespaceMatchesFolderStructureHeader);

            int startIndex = Path.GetDirectoryName(this.filePath).IndexOf("Echo") + 5;

            string testDirectory = Path.GetDirectoryName(filePath).Substring(startIndex).Replace("\\", ".");

            string testNamespace = elements.GetNamespace();

            if (!testNamespace.Replace("_", " ").Equals(testDirectory.Replace("_", " ")))
            {
                validated = false;

                this.reportColoredBox.AppendText(FAILED, Color.Red);
                validateNamespaceMatchesFolderStructure = "\n-Namespace: " + testNamespace + "\n Folder structure: " + testDirectory;

                this.reportColoredBox.AppendText(validateNamespaceMatchesFolderStructure, Color.Red);
            }
            else
                this.reportColoredBox.AppendText(PASSED, Color.Green);

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private bool ValidateUsings()
        {
            bool validated = true;
            string validateUsingResults = "";

            List<AstNode> usings = elements.UsingDeclarations;
            List<AstNode> sortedUsings = usings.OrderBy(node => node.GetText()).ToList<AstNode>();

            validated = usings.SequenceEqual(sortedUsings);

            this.reportColoredBox.AppendText(UsingsSortedHeader);

            if (validated)
            {
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;

                string usingsStr = "Usings Order:\n" + this.PrintList(usings);

                validateUsingResults = usingsStr;
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateUsingResults, Color.Red);
            }

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private bool ValidateFixtureSetupAndFixtureTeardownLocation()
        {
            bool validated = true;
            string validateFixtureSetupAndFixtureTeardownLocation = string.Empty;

            string firstMethod = elements.MethodDeclarations[0].GetText().Substring(
                0, elements.MethodDeclarations[0].GetText().IndexOf("]") + 1);
            string secondMethod = elements.MethodDeclarations[1].GetText().Substring(
                0, elements.MethodDeclarations[1].GetText().IndexOf("]") + 1);

            this.reportColoredBox.AppendText(SetUpAtTopHeader);

            // run if configured
            if (!firstMethod.Equals("[FixtureSetUp]"))
            {
                validateFixtureSetupAndFixtureTeardownLocation +=
                    string.Format(
                        "- Fixture Setup must be the first method at the top of the script, found this instead: {0}\r\n",
                        firstMethod);
                validated = false;
            }

            if (!secondMethod.Equals("[FixtureTearDown]"))
            {
                validateFixtureSetupAndFixtureTeardownLocation +=
                    string.Format(
                        "- Fixture Teardown must be the second method at the top of the script, found this instead: {0}\r\n",
                        secondMethod);
                validated = false;
            }

            if (validated)
            {
                validateFixtureSetupAndFixtureTeardownLocation =
                    string.Format(validateFixtureSetupAndFixtureTeardownLocation, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateFixtureSetupAndFixtureTeardownLocation =
                    string.Format(validateFixtureSetupAndFixtureTeardownLocation, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateFixtureSetupAndFixtureTeardownLocation, Color.Red);
            }

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private bool ValidateTryStatements()
        {
            bool validated = true;
            string validateTryStatementsResults = " ";

            this.reportColoredBox.AppendText(TryCatchHeader);

            if (elements.TryCatchStatements.Count > 0)
                validated = false;

            foreach (AstNode node in elements.TryCatchStatements)
            {
                validateTryStatementsResults += string.Format("- Try-Catch statement found at line {0}\r\n", node.StartLocation.Line);
            }

            if (validated)
            {
                validateTryStatementsResults = string.Format(validateTryStatementsResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;

                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateTryStatementsResults, Color.Red);
            }

            return validated;
        }

        private bool ValidateNoThreadSleeps()
        {
            bool validated = true;
            string validateNoThreadSleepsResults = " ";

            this.reportColoredBox.AppendText(SleepsHeader);

            if (elements.ExpressionStatements.Count == 0)
            {
                validated = false;
            }

            foreach (AstNode node in elements.ExpressionStatements)
            {
                if (node.GetText().Replace(" ", string.Empty).Contains("Thread.Sleep("))
                {
                    validated = false;
                    validateNoThreadSleepsResults += string.Format(
                        "- Thread.Sleep(...) statement found at line {0}\r\n", node.StartLocation.Line);
                }
            }

            if (validated)
            {
                validateNoThreadSleepsResults = string.Format(validateNoThreadSleepsResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateNoThreadSleepsResults, Color.Red);
            }

            return validated;
        }

        private bool ValidateNoConditionalStatements()
        {
            bool validated = true;
            string validateNoConditionalStatementsResults = string.Empty;

            this.reportColoredBox.AppendText(ConditionalStatementsHeader);

            if (elements.IfElseStatements.Count > 0 || elements.SwitchStatements.Count > 0 || elements.WhileStatements.Count > 0 || elements.ForStatements.Count > 0 || elements.ForEachStatements.Count > 0)
            {
                validated = false;
            }

            foreach (AstNode node in elements.IfElseStatements)
            {
                validateNoConditionalStatementsResults += string.Format(
                    "- IF statement found at line {0}\r\n", node.StartLocation.Line);
            }

            foreach (AstNode node in elements.SwitchStatements)
            {
                validateNoConditionalStatementsResults += string.Format(
                    "- Switch statement found at line {0}\r\n", node.StartLocation.Line);
            }

            foreach (AstNode node in elements.WhileStatements)
            {
                validateNoConditionalStatementsResults += string.Format(
                    "- While loop found at line {0}\r\n", node.StartLocation.Line);
            }

            foreach (AstNode node in elements.ForStatements)
            {
                validateNoConditionalStatementsResults += string.Format(
                    "- For Loop found at line {0}\r\n", node.StartLocation.Line);
            }

            foreach (AstNode node in elements.ForEachStatements)
            {
                validateNoConditionalStatementsResults += string.Format(
                    "- ForEach loop found at line {0}\r\n", node.StartLocation.Line);
            }

            if (validated)
            {
                validateNoConditionalStatementsResults = string.Format(validateNoConditionalStatementsResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateNoConditionalStatementsResults = string.Format(validateNoConditionalStatementsResults, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateNoConditionalStatementsResults, Color.Red);
            }

            return validated;
        }

        private bool ValidateRequiredCategoryAndAuthorAttributes()
        {
            bool categoryValidated = false;
            bool authorValidated = false;
            string validateRequiredCategoryAndAuthorAttributesResults = string.Empty;

            this.reportColoredBox.AppendText(CatAttributeHeader);

            foreach (AstNode node in elements.AttributeSections)
            {
                if (node.GetText().StartsWith("[Category"))
                {
                    categoryValidated = true;
                }

                if (node.GetText().StartsWith("[Author"))
                {
                    authorValidated = true;
                }
            }

            if (categoryValidated && authorValidated)
            {
                validateRequiredCategoryAndAuthorAttributesResults =
                    string.Format(validateRequiredCategoryAndAuthorAttributesResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateRequiredCategoryAndAuthorAttributesResults =
                    string.Format(validateRequiredCategoryAndAuthorAttributesResults, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
            }

            if (!categoryValidated)
            {
                validateRequiredCategoryAndAuthorAttributesResults += "- Category Attribute not found\r\n";
            }

            if (!authorValidated)
            {
                validateRequiredCategoryAndAuthorAttributesResults += "- Author Attribute not found\r\n";
            }

            this.reportColoredBox.AppendText(" ");

            return categoryValidated && authorValidated;
        }

        private bool ValidateOverallTimeout()
        {
            bool validated = true;
            string validateOverallTimeOutResults = "";

            this.reportColoredBox.AppendText(TimeoutHeader);

            if (elements.TimeoutAttributes.Count > 0)
            {
                if (elements.TimeoutAttributes[0].Ancestors.ToList()[0].GetText().Substring(
                        0, elements.TimeoutAttributes[0].Ancestors.ToList()[0].GetText().IndexOf("]") + 1).Equals(
                            "[TestFixture]"))
                {
                    string timeoutAttribute = elements.TimeoutAttributes[0].GetText();

                    int startPos = timeoutAttribute.IndexOf("(") + 1;
                    int length = timeoutAttribute.IndexOf(")") - startPos;

                    int value = Convert.ToInt32(timeoutAttribute.Substring(startPos, length).Trim());

                    int testFixtureTimeout = value;
                    int totalTimeout = 0;

                    for (int i = 1; i < elements.TimeoutAttributes.Count; i++)
                    {
                        timeoutAttribute = elements.TimeoutAttributes[i].GetText();

                        startPos = timeoutAttribute.IndexOf("(") + 1;
                        length = timeoutAttribute.IndexOf(")") - startPos;

                        value = Convert.ToInt32(timeoutAttribute.Substring(startPos, length).Trim());

                        if (value < 0)
                        {
                            validated = false;
                            validateOverallTimeOutResults += string.Format(
                                "- Negative timeout found at line {0}\r\n", elements.TimeoutAttributes[0].StartLocation.Line);
                        }

                        totalTimeout += value;
                    }

                    if (totalTimeout > testFixtureTimeout)
                    {
                        validated = false;
                        validateOverallTimeOutResults +=
                            string.Format(
                                "- TestFixture Timeout is {0} seconds and the sum of the test case Timeouts is {1} seconds\r\n",
                                testFixtureTimeout,
                                totalTimeout);
                    }
                }
            }

            if (validated)
            {
                validateOverallTimeOutResults = string.Format(validateOverallTimeOutResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateOverallTimeOutResults, Color.Red);
            }

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private bool ValidateZeroTimeouts()
        {
            bool validated = true;
            string validateZeroTimeOutResults = "";

            string timeoutAttribute = string.Empty;
            int startPos;
            int length;
            int value;

            for (int i = 0; i < elements.TimeoutAttributes.Count; i++)
            {
                timeoutAttribute = elements.TimeoutAttributes[i].GetText();

                startPos = timeoutAttribute.IndexOf("(") + 1;
                length = timeoutAttribute.IndexOf(")") - startPos;

                value = Convert.ToInt32(timeoutAttribute.Substring(startPos, length).Trim());

                if (value == 0)
                {
                    validated = false;
                    validateZeroTimeOutResults += string.Format(
                        "- [Timeout = 0] found at line {0}\r\n", elements.TimeoutAttributes[i].StartLocation.Line);
                }
            }

            this.reportColoredBox.AppendText(zeroTimeoutHeader);

            if (validated)
            {
                validateZeroTimeOutResults = string.Format(validateZeroTimeOutResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateZeroTimeOutResults = string.Format(validateZeroTimeOutResults, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateZeroTimeOutResults, Color.Red);
            }

            return validated;
        }

        static void IterateStatement(TSqlStatement statement)
        {
            Console.WriteLine("New Statement");

            if (statement is SelectStatement)
            {
                //PrintStatement(sstmnt);
            }
        }


        //TODO: Complete validation
        private bool ValidateModifiedDatabaseIsBackedUpAndRestored()
        {
            bool validated1 = true, validated2 = true, validated3 = true;
            string validateModifiedDatabaseResults = string.Empty;

            this.reportColoredBox.AppendText(DatabaseBackupHeader);
            /*
            // Initialized queries
            List<AstNode> variableInitializerNodes = this.elements.VariableInitializerStatements;
            List<AstNode> variableDeclarationStatements = this.elements.VariableDeclarationStatements;

            // Inline query execution and AddRollBacks
            List<AstNode> invocationNodes = this.elements.InvocationExpressions;

            List<string> modifyTableList = new List<string>();

            foreach (AstNode node in variableInitializerNodes)
            {

                var parser = new TSql100Parser(false);

                IList<ParseError> Errors = new List<ParseError>();

                IScriptFragment fragment = parser.Parse(
                    new StringReader(node.GetText().Substring(node.GetText().IndexOf("= ") + 2).Replace("\"", "").Replace("@", "")),
                    out Errors);

                var Script = fragment as TSqlScript;

                foreach (var ts in Script.Batches)
                {
                    Console.WriteLine("new batch");

                    foreach (var st in ts.Statements)
                    {
                        IterateStatement(st);
                    }
                }

                string TableName = @"(INSERT|UPDATE|DELETE)\s*(INTO|\w+)\s*(\w+)\s*(\(|VALUES|SET)";
                Regex ValidLine = new Regex(TableName, RegexOptions.Compiled | RegexOptions.IgnoreCase);

                var currentTableName = ValidLine.Match(node.GetText().ToUpper());
                var value = currentTableName.Groups[3].Value;

                if (!modifyTableList.Contains(value) && !string.IsNullOrEmpty(value))
                {
                    modifyTableList.Add(value);
                }
            }
            */

            if (validated1 && validated2 && validated3)
            {
                validateModifiedDatabaseResults = string.Format(validateModifiedDatabaseResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateModifiedDatabaseResults = string.Format(validateModifiedDatabaseResults, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
            }

            this.reportColoredBox.AppendText(validateModifiedDatabaseResults, Color.Red);
            this.reportColoredBox.AppendText(" ");

            return validated1 && validated2 && validated3;
        }

        private bool ValidateTestsFollowBDD()
        {
            bool validated = true;
            string validateDBBResults = string.Empty;
            string methodName = string.Empty;
            int methodNodeStartLocationLine = -1;

            this.reportColoredBox.AppendText(BDDHeader);

            foreach (AstNode node in this.elements.TestMethods)
            {
                foreach (AstNode child in node.Children)
                {
                    if (child.GetType().Name.Equals("Identifier"))
                    {
                        methodName = child.GetText();
                    }
                }

                methodNodeStartLocationLine = node.StartLocation.Line;

                if (node.LastChild.Children.ToList()[1].GetText().ToUpper().StartsWith("#region Given".ToUpper()))
                {
                    int i = 1;
                    List<AstNode> methodChildren = node.LastChild.Children.ToList();

                    i = i + 1;
                    int x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                    i = x + 1;

                    while (methodChildren[i].GetText().ToUpper().StartsWith("#region And".ToUpper()))
                    {
                        i = i + 1;
                        x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                        i = x + 1;
                    }

                    if (methodChildren[i].GetText().ToUpper().StartsWith("#region When".ToUpper()))
                    {
                        i = i + 1;
                        x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                        i = x + 1;

                        while (methodChildren[i].GetText().ToUpper().StartsWith("#region And".ToUpper()))
                        {
                            i = i + 1;
                            x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                            i = x + 1;
                        }

                        if (methodChildren[i].GetText().ToUpper().StartsWith("#region Then".ToUpper()))
                        {
                            i = i + 1;
                            x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                            i = x + 1;

                            while (methodChildren[i].GetText().ToUpper().StartsWith("#region And".ToUpper()))
                            {
                                i = i + 1;
                                x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                                i = x + 1;
                            }

                            while (methodChildren[i].GetText().ToUpper().StartsWith("#region Therefore".ToUpper()))
                            {
                                i = i + 1;
                                x = elements.FindEndRegion(node.LastChild.Children.ToList(), i);
                                i = x + 1;
                            }

                            if (!methodChildren[i].GetText().StartsWith("}"))
                            {
                                validated = false;
                                validateDBBResults +=
                                    string.Format(
                                        "- Test Case: {0} at line: {1} does not follow DBB format\r\n\tIssue Found at line: {2}: A Then can only be followed by And(s)\r\n",
                                        methodName,
                                        methodNodeStartLocationLine,
                                        methodChildren[i].StartLocation.Line);
                            }
                        }
                        else
                        {
                            // no then found
                            validated = false;
                            validateDBBResults +=
                                string.Format(
                                    "- Test Case: {0} at line: {1} does not follow DBB format\r\n\tIssue Found at line: {2}:A When must be followed by And(s) or a Then\r\n",
                                    methodName,
                                    methodNodeStartLocationLine,
                                    methodChildren[i].StartLocation.Line);
                        }
                    }
                    else
                    {
                        // no when found
                        validated = false;
                        validateDBBResults +=
                            string.Format(
                                "- Test Case: {0} at line: {1} does not follow DBB format\r\n\tIssue Found at line: {2}: A Given must be followed by And(s) and a When\r\n",
                                methodName,
                                methodNodeStartLocationLine,
                                methodChildren[i].StartLocation.Line);
                    }
                }
                else
                {
                    // no given found
                    validated = false;
                    validateDBBResults +=
                        string.Format(
                            "- Test Case: {0} at line: {1} does not follow DBB format.\r\n\tIssue Found at line {2}: Test case must start with a Given\r\n",
                            methodName,
                            methodNodeStartLocationLine,
                            node.LastChild.StartLocation.Line);
                }
            }

            if (validated)
            {
                validateDBBResults = string.Format(validateDBBResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateDBBResults = string.Format(validateDBBResults, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateDBBResults, Color.Red);
            }

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private bool ValidateNoSystemConsoleOrSystemLogUsage()
        {
            bool validated = true;

            string validateNoSystemConsoleOrSystemLogResults = string.Empty;

            this.reportColoredBox.AppendText(ConsoleHeader);

            if (elements.ConsoleWriteStatements.Count > 0 || elements.ConsoleLogStatements.Count > 0)
                validated = false;

            foreach (AstNode node in elements.ConsoleWriteStatements)
                validateNoSystemConsoleOrSystemLogResults += string.Format("- Console.Write... statement found at line {0}\r\n", node.StartLocation.Line);

            foreach (AstNode node in elements.ConsoleLogStatements)
                validateNoSystemConsoleOrSystemLogResults += string.Format("- Console.Log(...) statement found at line {0}\r\n", node.StartLocation.Line);

            if (validated)
            {
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateNoSystemConsoleOrSystemLogResults, Color.Red);
            }

            return validated;
        }

        private bool ValidateDescriptiveLambdaExpressions()
        {
            bool validated = true;

            string validateDescriptiveLambdaExpressionsResults = string.Empty;

            this.reportColoredBox.AppendText(LambdaHeader);

            foreach (AstNode node in elements.LambdaExpressions)
            {
                if (!node.Parent.GetText().Contains("PayrollWaiter")) // Exclude PayrollWaiter Lambda
                {
                    string lambdaIndentifier1 = node.GetText().Substring(0, node.GetText().IndexOf("=>") - 1);
                    string lambdaIndentifier2 = node.GetText().Substring(
                        node.GetText().IndexOf("=>") + 3, lambdaIndentifier1.Length);

                    if (lambdaIndentifier1.Length <= 2)
                    {
                        validated = false;
                        validateDescriptiveLambdaExpressionsResults +=
                            string.Format(
                                "- Labmda Expression not descriptive enough at line {0}. Found {1}\r\n",
                                node.StartLocation.Line,
                                node.GetText());
                    }
                }
            }

            if (validated)
            {
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                this.reportColoredBox.AppendText(FAILED, Color.Red);
                this.reportColoredBox.AppendText(validateDescriptiveLambdaExpressionsResults, Color.Red);
            }

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private bool ValidateNoUseOfDatabaseConnectionsNotProvidedByECHO()
        {
            bool validated = true;
            string validateNoUseOfDatabaseConnectionsNotProvidedByECHOResults = " ";

            this.reportColoredBox.AppendText(NoDatabaseOutsideEchoHeader);

            if (elements.ExpressionStatements.Count == 0)
                validated = false;

            foreach (AstNode node in elements.ExpressionStatements)
            {
                if (node.GetText().Replace(" ", string.Empty).Contains("SqlConnection"))
                {
                    validated = false;
                    validateNoUseOfDatabaseConnectionsNotProvidedByECHOResults +=
                        String.Format("- SqlConnection found at line {0}\r\n", node.StartLocation.Line);
                }
            }

            if (validated)
            {
                validateNoUseOfDatabaseConnectionsNotProvidedByECHOResults = String.Format(validateNoUseOfDatabaseConnectionsNotProvidedByECHOResults, PASSED);
                this.reportColoredBox.AppendText(PASSED, Color.Green);
            }
            else
            {
                this.failCount++;
                validateNoUseOfDatabaseConnectionsNotProvidedByECHOResults = String.Format(validateNoUseOfDatabaseConnectionsNotProvidedByECHOResults, FAILED);
                this.reportColoredBox.AppendText(FAILED, Color.Red);
            }

            this.reportColoredBox.AppendText(" ");

            return validated;
        }

        private string PrintList(List<AstNode> list)
        {
            string listStr = "";

            foreach (AstNode node in list)
            {
                if (string.IsNullOrEmpty(listStr))
                    listStr += "\t" + node.GetText().Replace("\r\n", "");
                else
                    listStr += "\n\t" + node.StartLocation.Line + ": " + node.GetText().Replace("\r\n", "");
            }

            return listStr;
        }
    }
}
